﻿using System;
using System.Data;
using System.Data.OracleClient;
using System.Diagnostics;
using System.Threading;
using System.Windows.Threading;
using ExThreading;
using ReflectionStudio.Core.Database; 
using WPFExcelReport;
namespace ReflectionStudio.Core.Events
{
    public class EventDispatcher : DispatcherObject
    {
        public class ExWorkItem : WorkItem
        {
            public DataRow dwThis;
            public WorkQueue thisWork;
            BaseFunction m_base;
            string mFunction = "AB05AV95Data";
            OracleConnection OracleDB;
            IntexReptServBLClient proxy;
            INTEXDataSet setUI;
            public ExWorkItem(DataRow dwThis, DispatcherObject dispatcher, BaseFunction mbase, WorkQueue wq)
                : base()
            {
                this.dwThis = dwThis;
                this.thisWork = wq;
                m_base = mbase;
            }
            public ExWorkItem(DataRow dwThis, string mbase, OracleConnection _OracleDB, IntexReptServBLClient _proxy, WorkQueue wq, INTEXDataSet _setUI)
                : base()
            {
                this.dwThis = dwThis;
                this.thisWork = wq;
                mFunction = mbase;
                OracleDB = _OracleDB;
                proxy = _proxy;
                setUI = _setUI;
            }
            public override void Perform()
            {

                /*
                switch (mFunction)
                {                    
                    case "AB05AV95Data":
                        m_base = new WPFExcelReport.AB05AV95Data(OracleDB, proxy);
                        break;
                    case "AB50AV95Data":
                        m_base = new WPFExcelReport.AB50AV95Data(OracleDB, proxy);
                        break;
                    case "AB45AV95Data":
                        m_base = new WPFExcelReport.AB45AV95Data(OracleDB, proxy, setUI);
                        break;
                    case "ABINFOData":
                        m_base = new WPFExcelReport.ABINFOData(OracleDB, proxy, setUI);
                        break;               
                    default:
                        break;
                }*/
                thisWork.dispatcher.Dispatcher.Invoke(m_base.m_UI, DispatcherPriority.Background, dwThis);

                //ThisResource.ProcessWFMessage(ThisMessage);
                //这里要通知主线程进行处理
            }
            public override string ToString()
            {
                return mFunction;
            }
        }
        #region ----------------SINGLETON----------------
        public static readonly EventDispatcher Instance = new EventDispatcher();
        public WorkQueue work; 
        public int FinishedJobs = 0;
        public int TotalJobs = 0;
        BaseFunction m_BF;
        /// <summary>
        /// Private constructor for singleton pattern
        /// </summary>
        private EventDispatcher()
        {
            work = new WorkQueue();

            work.ConcurrentLimit = 150;
            work.dispatcher = this;
            ((WorkThreadPool)work.WorkerPool).MaxThreads = 30;
            ((WorkThreadPool)work.WorkerPool).MinThreads = 2;
            work.AllWorkCompleted += new EventHandler(work_AllWorkCompleted);
            work.WorkerException += new ResourceExceptionEventHandler(work_WorkerException);
            work.ChangedWorkItemState += new ChangedWorkItemStateEventHandler(work_ChangedWorkItemState);
         }
        public void BuildABPOS(DataRow dwABPOS)
        {
            //m_BF.BuildABPOS(dwABPOS);
        }
        #endregion

        #region ----------------STATUS BAR----------------
        /// <summary>
        /// Event delegate
        /// </summary>
        public event EventHandler<StatusEventArgs> OnStatusChange;

        /// <summary>
        /// Internal function to raise a status (bar) event
        /// </summary>
        /// <param name="type"></param>
        public void RaiseStatus(string message, StatusEventType type)
        {
            if (message.Contains("查询进展"))
            {
                FinishedJobs++;
            }

            message = message.Replace("<-FinishedJobs->", FinishedJobs.ToString());
            message = message.Replace("<-TotalJobs->", work.TotalJobs.ToString());
            if (FinishedJobs == work.TotalJobs
                && FinishedJobs > 0
                && work.TotalJobs > 0)
            {
                message = message.Replace("查询进展", "全部完成");
                type = StatusEventType.StopProgress;
            }
            Trace.TraceInformation(message);

            if (CheckAccess())
            {
                StatusEventArgs args = new StatusEventArgs(type, message);

                if (OnStatusChange != null)
                    OnStatusChange(this, args);

                //raise event only if it contains message
                if (message != string.Empty)
                    RaiseMessage(args);
            }
            else
                Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
                {
                    StatusEventArgs args = new StatusEventArgs(type, message);
                    args.Info.Details.Replace("FinishedJobs", FinishedJobs.ToString());
                    if (OnStatusChange != null)
                        OnStatusChange(this, args);

                    //raise event only if it contains message
                    if (message != string.Empty)
                        RaiseMessage(args);
                });
        }

        #endregion 
        #region ----------------MESSAGE----------------
        /// <summary>
        /// Event delegate
        /// </summary>
        public event EventHandler<MessageEventArgs> OnMessage;

        public void RaiseMessage(MessageInfo info)
        {
            RaiseMessage(new MessageEventArgs(info));
        }


        /// <summary>
        /// Internal function to raise an event
        /// </summary>
        /// <param name="type"></param>
        private void RaiseMessage(MessageEventArgs args)
        {
            Trace.Assert(args != null);

            if (CheckAccess())
            {
                if (OnMessage != null)
                    OnMessage(this, args);
            }
            else
                Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
                {
                    if (OnMessage != null)
                        OnMessage(this, args);
                });
        }

        private void RaiseMessage(string message)
        {
            Trace.TraceInformation(message);

            if (CheckAccess())
            {
                MessageEventArgs args = new MessageEventArgs(message);

                if (OnMessage != null)
                    OnMessage(this, args);
            }
            else
                Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
                {
                    MessageEventArgs args = new MessageEventArgs(message);

                    if (OnMessage != null)
                        OnMessage(this, args);
                });
        }

        #endregion

        #region ------------------MultiThread------------------
        public void RaiseUIMessage(BaseFunction m_Base, DataRow dwinfo)
        {
            BuildWorkQueue(m_Base, dwinfo);
        }
        public void RaiseUIMessage(string m_Base, DataRow dwinfo, OracleConnection _OracleDB, IntexReptServBLClient _proxy, INTEXDataSet _setUI)
        {
            BuildWorkQueue(m_Base, dwinfo, _OracleDB, _proxy, _setUI);
        }
        public void BuildWorkQueue(string m_Base, DataRow dwinfo, OracleConnection _OracleDB, IntexReptServBLClient _proxy, INTEXDataSet _setUI)
        {
            ExWorkItem ThisWorkItem = new ExWorkItem(dwinfo, m_Base, _OracleDB, _proxy, work, _setUI);
            work.Add(ThisWorkItem);
        }
        public void BuildWorkQueue(BaseFunction m_Base, DataRow dwABPOS)
        {
            ExWorkItem ThisWorkItem = new ExWorkItem(dwABPOS, m_Base, m_Base, work);
            work.Add(ThisWorkItem);
        }

        private void work_ChangedWorkItemState(object sender, ChangedWorkItemStateEventArgs e)
        {
            lock (this)
            {
                ExWorkItem exWinWI = (ExWorkItem)e.WorkItem;
                WorkItemState state = exWinWI.State;
                if (state == WorkItemState.Completed)
                {
                    DataRow dwThis = exWinWI.dwThis;
                    //this.Dispatcher.BeginInvoke(m_UI, DispatcherPriority.Background, dwThis); 
                }
            }
        }

        private void work_AllWorkCompleted(object sender, EventArgs e)
        {

            if (this.Dispatcher.CheckAccess())
            {
                this.Dispatcher.BeginInvoke(new EventHandler(work_AllWorkCompleted), DispatcherPriority.Background, new object[] { sender, e });
            }
        }
        private void work_WorkerException(object sender, ResourceExceptionEventArgs ex)
        {
            Tracer.Error(ex.Exception.StackTrace, ex.Exception);
        }
        #endregion
    }
}
